/*****************************************************************************
* File Name: flash.c
*
* Version: 1.0
*
* Description:
* This file contains API to store and retrieve data from the flash
*
* Note:
* Defining DISABLE_FLASH in platform.h to disable flash module
*
* Owner: MRAO
*
* Related Document:
* System Reference Guide
* BLE Component data sheet
*
* Hardware Dependency:
* PRoC BLE Family of Devices
*
* Code Tested With:
* 1. PSoC Creator 3.1
* 2. ARM GCC 4.8.4
******************************************************************************
* Copyright (2015), Cypress Semiconductor Corporation.
******************************************************************************
* This software is owned by Cypress Semiconductor Corporation (Cypress) and is
* protected by and subject to worldwide patent protection (United States and
* foreign), United States copyright laws and international treaty provisions.
* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable
* license to copy, use, modify, create derivative works of, and compile the
* Cypress Source Code and derivative works for the sole purpose of creating
* custom software in support of licensee product to be used only in conjunction
* with a Cypress integrated circuit as specified in the applicable agreement.
* Any reproduction, modification, translation, compilation, or representation of
* this software except as specified above is prohibited without the express
* written permission of Cypress.
*
* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
* Cypress reserves the right to make changes without further notice to the
* materials described herein. Cypress does not assume any liability arising out
* of the application or use of any product or circuit described herein. Cypress
* does not authorize its products for use as critical components in life-support
* systems where a malfunction or failure may reasonably be expected to result in
* significant injury to the user. The inclusion of Cypress' product in a life-
* support systems application implies that the manufacturer assumes all risk of
* such use and in doing so indemnifies Cypress against all charges. Use may be
* limited by and subject to the applicable Cypress software license agreement.
*****************************************************************************/
#include "flash.h"

#ifndef DISABLE_FLASH

#ifndef DISABLE_BLE
extern bool Ble_Enter_LowPowerMode(void);
#endif /* DISABLE_BLE */

/*****************************************************************************
* Function Name: Flash_Calc_Checksum()
******************************************************************************
* Summary:
* This function is used to calculate the check sum for the buffer
*
* Parameters:
* uint8 *ptr - pointer to the buffer 
* uint8 byteCount - number of the bytes to be written 
*
* Return:
* uint8 - check sum calulated
*
* Theory:
* This API adds all the data in the buffer and does the compliment of the sum
*
* Side Effects:
* None
*
* Note:
* None
*****************************************************************************/
static uint8 Flash_Calc_Checksum (uint8 *ptr, uint32 size)
{
    uint32 index;
    uint8 checksum = 0;

    if (ptr == NULL)
    {
        return 0;
    }

    for (index = 0; index < size; index++)
    {
        checksum += ptr[index];
    }

    return ((uint8)(1u) + (uint8)(~checksum));
}

/*****************************************************************************
* Function Name: Flash_Save()
******************************************************************************
* Summary:
* This function is used to store the data into the flash
*
* Parameters:
* uint8 *srcBuf - pointer to the source buffer 
* uint8 *flashPtr - pointer to the variable in the flash
* uint8 byteCount - number of the bytes to be written 
*
* Return:
* bool - true if flash write is successful 
*
* Theory:
* This API identifies the row number in the flash through the address supplied. 
* It reads the data from flash row number and replaces with the source buffer. It 
* writes the data back into the flash
*
* Side Effects:
* None
*
* Note:
* 1) It is the responsibility of the user to the make sure that the buffer allocated for 
* the flash and the source buffer is equal or more than the byte count 
* 2) The first byte need to be checksum
*****************************************************************************/
bool Flash_Save(uint8 *srcBuf, const uint8 flashPtr[], uint32 byteCount)
{
#ifdef DISABLE_BLE
    uint8 writeBuffer[CY_FLASH_SIZEOF_ROW];
    uint32 rowId;
    uint32 dstIndex;
    uint32 srcIndex;
    cystatus rc;
    uint32 eeOffset;
    uint32 byteOffset;
    bool result = true;
    eeOffset = (uint32)flashPtr;
    /* A check to make sure same data is not written into the flash */ 
    if((flashPtr == NULL) || (srcBuf == NULL) || (byteCount <= 1))
    {
        return false;
    }
    *srcBuf = Flash_Calc_Checksum((srcBuf+1), (byteCount-1));
    if(memcmp(srcBuf,flashPtr, byteCount) == 0)
    {
        return false;
    }
    
    if (((uint32)flashPtr + byteCount) < (CYDEV_FLASH_BASE + CYDEV_FLASH_SIZE))
    {
        rowId = (eeOffset / CY_FLASH_SIZEOF_ROW);
        byteOffset = (CY_FLASH_SIZEOF_ROW * rowId);
        srcIndex = 0u;

        rc = CYRET_SUCCESS;

        while ((srcIndex < byteCount) && (CYRET_SUCCESS == rc))
        {
            /* Copy data to the write buffer either from the source buffer or from the flash */
            for (dstIndex = 0u; dstIndex < CY_FLASH_SIZEOF_ROW; dstIndex++)
            {
                if ((byteOffset >= eeOffset) && (srcIndex < byteCount))
                {
                    writeBuffer[dstIndex] = srcBuf[srcIndex];
                    srcIndex++;
                }
                else
                {
                    writeBuffer[dstIndex] = CY_GET_XTND_REG8(CYDEV_FLASH_BASE + byteOffset);
                }
                byteOffset++;
            }

            /* Write flash row */
            rc = CySysFlashWriteRow(rowId, writeBuffer);
            

            /* Go to the next row */
            rowId++;
        }
    }
    else
    {
        rc = CYRET_BAD_PARAM;
    }

    /* Mask return codes from flash, if they are not supported */
    if (CYRET_SUCCESS != rc)
    {
        result = false;
    }
    
    return (result);
#else
    CYBLE_API_RESULT_T apiResult;
    if((flashPtr == NULL) || (srcBuf == NULL) || (byteCount <= sizeof(uint8)))
    {
        return false;
    }

    *srcBuf = Flash_Calc_Checksum((srcBuf+1), (byteCount-1));
    if (memcmp(srcBuf, flashPtr, byteCount) == 0)
    {
        return true;
    }

    CyBle_ExitLPM();
    apiResult = CyBle_StoreAppData(srcBuf, flashPtr, byteCount, true);
    Ble_Enter_LowPowerMode();
    return (apiResult == CYBLE_ERROR_OK);
#endif /* DISABLE_BLE */
}

/*****************************************************************************
* Function Name: Flash_Load()
******************************************************************************
* Summary:
* This function is used to restore the data in the flash to the RAM buffer
*
* Parameters:
* uint8 *flashPtr - pointer to the variable in the flash
* uint8 *destBuf - pointer to the source buffer
* uint8 byteCount - number of the bytes to be written 
*
* Return:
* bool - true if successful
*
* Theory:
* It copies the data from the flash address provided to the RAM address provided to 
* to the API
*
* Side Effects:
* None
*
* Note:
* It is the responsibility the user to make sure the buffer allocated for the flash and 
* the source buffer is equal or more than the byte count
* 2) The first byte need to be checksum
*****************************************************************************/
bool Flash_Load(const uint8 flashPtr[], uint8 *destBuf, uint32 byteCount)
{
    if((flashPtr == NULL) || (destBuf == NULL) || (byteCount <= sizeof(uint8)))
    {
        return false;
    }
    memcpy(destBuf, flashPtr, byteCount);
    if(Flash_Calc_Checksum((destBuf+1) ,(byteCount-1))  != *destBuf)
    {
        *destBuf = 0x0;        
        memset(destBuf+2, 0, (byteCount-2));
        return false;
    }
    return true;
}

#endif /* DISABLE_FLASH */
